/*******************************************************************************
 @file    dev_gpio.c
 @author  H.M.Shim (elecage@gmail.com)
 @version
 @date    2013. 7. 25.
 @brief GPIO 디바이스 드라이버의 구현
 ******************************************************************************
 The MIT License (MIT)

 Copyright (c) 2013 <copyright holders>

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "usbstdio.h"
#include "devio.h"
#include "dev_gpio.h"
#include "stm32f4xx.h"
#include "stm32f4xx_rcc.h"
#include "stm32f4xx_it.h"
#include "cmdline.h"
/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/
#define DEV_GPIOA_DEVICE_NAME ((int8_t*)"gpioa")	/**< @brief GPIO A 포트 장치명 */
#define DEV_GPIOB_DEVICE_NAME ((int8_t*)"gpiob")	/**< @brief GPIO B 포트 장치명 */
#define DEV_GPIOC_DEVICE_NAME ((int8_t*)"gpioc")	/**< @brief GPIO C 포트 장치명 */
#define DEV_GPIOD_DEVICE_NAME ((int8_t*)"gpiod")	/**< @brief GPIO D 포트 장치명 */
#define DEV_GPIOE_DEVICE_NAME ((int8_t*)"gpioe")	/**< @brief GPIO E 포트 장치명 */
#define DEV_GPIOF_DEVICE_NAME ((int8_t*)"gpiof")	/**< @brief GPIO F 포트 장치명 */
#define DEV_GPIOG_DEVICE_NAME ((int8_t*)"gpiog")	/**< @brief GPIO G 포트 장치명 */
#define DEV_GPIOH_DEVICE_NAME ((int8_t*)"gpioh")	/**< @brief GPIO H 포트 장치명 */
#define DEV_GPIOI_DEVICE_NAME ((int8_t*)"gpioi")	/**< @brief GPIO I 포트 장치명 */

#define NUM_GPIO		9
#define GPA				0
#define GPB				1
#define GPC				2
#define GPD				3
#define GPE				4
#define GPF				5
#define GPG				6
#define GPH				7
#define GPI				8

#define GPIO_ARG_PIN0			("pin0")	/**< @brief GPIO Pin 0를 세팅하라는 문자열 인자 */
#define GPIO_ARG_PIN1			("pin1")	/**< @brief GPIO Pin 1을 세팅하라는 문자열 인자 */
#define GPIO_ARG_PIN2			("pin2")	/**< @brief GPIO Pin 2를 세팅하라는 문자열 인자 */
#define GPIO_ARG_PIN3			("pin3")	/**< @brief GPIO Pin 3을 세팅하라는 문자열 인자 */
#define GPIO_ARG_PIN4			("pin4")	/**< @brief GPIO Pin 4를 세팅하라는 문자열 인자 */
#define GPIO_ARG_PIN5			("pin5")	/**< @brief GPIO Pin 5를 세팅하라는 문자열 인자 */
#define GPIO_ARG_PIN6			("pin6")	/**< @brief GPIO Pin 6을 세팅하라는 문자열 인자 */
#define GPIO_ARG_PIN7			("pin7")	/**< @brief GPIO Pin 7을 세팅하라는 문자열 인자 */
#define GPIO_ARG_PIN8			("pin8")	/**< @brief GPIO Pin 8을 세팅하라는 문자열 인자 */
#define GPIO_ARG_PIN9			("pin9")	/**< @brief GPIO Pin 9를 세팅하라는 문자열 인자 */
#define GPIO_ARG_PIN10			("pin10")	/**< @brief GPIO Pin 10을 세팅하라는 문자열 인자 */
#define GPIO_ARG_PIN11			("pin11")	/**< @brief GPIO Pin 11을 세팅하라는 문자열 인자 */
#define GPIO_ARG_PIN12			("pin12")	/**< @brief GPIO Pin 12를 세팅하라는 문자열 인자 */
#define GPIO_ARG_PIN13			("pin13")	/**< @brief GPIO Pin 13을 세팅하라는 문자열 인자 */
#define GPIO_ARG_PIN14			("pin14")	/**< @brief GPIO Pin 14를 세팅하라는 문자열 인자 */
#define GPIO_ARG_PIN15			("pin15")	/**< @brief GPIO Pin 15를 세팅하라는 문자열 인자 */


/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
Dev_Gpio_flag devGpioFlag[NUM_GPIO];				/**< @brief 각 GPIO 별 상태 flag */

/**
 * @brief 각 GPIO 별 장치명의 배열
 * GPIO를 open할 때 사용할 장치명을 저장한다.
 * GPIO의 갯수가 9개 이므로 9개의 배열로 구성되어 있다.
 */
int8_t *devGpioName[NUM_GPIO] = {DEV_GPIOA_DEVICE_NAME,
									   DEV_GPIOB_DEVICE_NAME,
									   DEV_GPIOC_DEVICE_NAME,
									   DEV_GPIOD_DEVICE_NAME,
									   DEV_GPIOE_DEVICE_NAME,
									   DEV_GPIOF_DEVICE_NAME,
									   DEV_GPIOG_DEVICE_NAME,
									   DEV_GPIOH_DEVICE_NAME,
									   DEV_GPIOI_DEVICE_NAME};

/**
 * @brief GPIO Type 지정 정의 변수 배열
 */
GPIO_TypeDef *gpio_Type[NUM_GPIO] = {GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH, GPIOI};

/**
 * @brief 각 외부 인터럽트에 대한 인터럽트 핸들러 배열
 * 인터럽트 핸들러는 총 16개의 핀에 대해 정의되어 있다. 각 포트의 핀들은 각 핀에  해당하는 외부 인터럽트 라인에 멀티플렉서로 연결되어 있으며
 * 개발자는 각 인터럽트 핀 별로 어느 GPIO에 연결할지를 결정할 수 있다.
 */
InterruptHandleFunc extiIsrFunc[16] = {HardFault_Handler,
									   HardFault_Handler,
									   HardFault_Handler,
									   HardFault_Handler,
									   HardFault_Handler,
									   HardFault_Handler,
									   HardFault_Handler,
									   HardFault_Handler,
									   HardFault_Handler,
									   HardFault_Handler,
									   HardFault_Handler,
									   HardFault_Handler,
									   HardFault_Handler,
									   HardFault_Handler,
									   HardFault_Handler,
									   HardFault_Handler,};
/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/

/**
 * @brief GPIO를 장치 리스트에 등록한다.
 * @retval 0 : 성공
 * GPIO를 사용하기 위해서는 registerDev_Gpio() 함수를 이용하여 먼저 장치 리스트에 등록해야 한다.
 */
int32_t registerDev_Gpio(void)
{
	int i, j;
	DeviceStructure devStructure;
	for(i = 0 ; i < NUM_GPIO ; i++) {
		devStructure.dd 			= Dev_GPIOA + i;
		devStructure.devname 		= devGpioName[i];
		devStructure.openFunc 		= dev_GpioOpen;
		devStructure.readFunc 		= dev_GpioRead;
		devStructure.writeFunc 		= dev_GpioWrite;
		devStructure.ioctlFunc 		= dev_GpioIoctl;
		devStructure.closeFunc 		= dev_GpioClose;
#ifdef USE_CMDLINE
		devStructure.openCmdFunc 	= dev_GpioOpenCmd;
		devStructure.readCmdFunc	= dev_GpioReadCmd;
		devStructure.writeCmdFunc	= dev_GpioWriteCmd;
		devStructure.ioctlCmdFunc	= dev_GpioIoctlCmd;
		devStructure.closeCmdFunc	= dev_GpioCloseCmd;
#endif /* USE_CMDLINE */

		devGpioFlag[i].stat = 0;

		for( j = 0 ; j < 16 ; j++) {
			devGpioFlag[i].rdwr[j] = (int8_t)(DEV_RDWR >> 4);
		}

		registerDevice(devStructure);
	}

	return 0;
}


/**
 * @brief GPIO 장치를 사용 가능하도록 한다..
 * @param devname : 장치명
 * @param flags : 장치의 플래그
 *   - DEV_RDONLY : 장치를 읽기 전용 모드로 연다.
 *   - DEV_WRONLY : 장치를 쓰기 전용 모드로 연다.
 *   - DEV_RDWR : 장치를 읽기/쓰기가 모두 가능하도록 한다.
 *   - GPIO_Pin_0 : GPIO Pin 0에 대해 설정한다. 즉, 나머지 핀에 대해서는 설정하지 않는다.
 *   - GPIO_Pin_1 : GPIO Pin 1에 대해 설정한다. 즉, 나머지 핀에 대해서는 설정하지 않는다.
 *   - GPIO_Pin_2 : GPIO Pin 2에 대해 설정한다. 즉, 나머지 핀에 대해서는 설정하지 않는다.
 *   - GPIO_Pin_3 : GPIO Pin 3에 대해 설정한다. 즉, 나머지 핀에 대해서는 설정하지 않는다.
 *   - GPIO_Pin_4 : GPIO Pin 4에 대해 설정한다. 즉, 나머지 핀에 대해서는 설정하지 않는다.
 *   - GPIO_Pin_5 : GPIO Pin 5에 대해 설정한다. 즉, 나머지 핀에 대해서는 설정하지 않는다.
 *   - GPIO_Pin_6 : GPIO Pin 6에 대해 설정한다. 즉, 나머지 핀에 대해서는 설정하지 않는다.
 *   - GPIO_Pin_7 : GPIO Pin 7에 대해 설정한다. 즉, 나머지 핀에 대해서는 설정하지 않는다.
 *   - GPIO_Pin_8 : GPIO Pin 8에 대해 설정한다. 즉, 나머지 핀에 대해서는 설정하지 않는다.
 *   - GPIO_Pin_9 : GPIO Pin 9에 대해 설정한다. 즉, 나머지 핀에 대해서는 설정하지 않는다.
 *   - GPIO_Pin_10 : GPIO Pin 10에 대해 설정한다. 즉, 나머지 핀에 대해서는 설정하지 않는다.
 *   - GPIO_Pin_11 : GPIO Pin 11에 대해 설정한다. 즉, 나머지 핀에 대해서는 설정하지 않는다.
 *   - GPIO_Pin_12 : GPIO Pin 12에 대해 설정한다. 즉, 나머지 핀에 대해서는 설정하지 않는다.
 *   - GPIO_Pin_13 : GPIO Pin 13에 대해 설정한다. 즉, 나머지 핀에 대해서는 설정하지 않는다.
 *   - GPIO_Pin_14 : GPIO Pin 14에 대해 설정한다. 즉, 나머지 핀에 대해서는 설정하지 않는다.
 *   - GPIO_Pin_15 : GPIO Pin 15에 대해 설정한다. 즉, 나머지 핀에 대해서는 설정하지 않는다.
 * @return 디바이스 디스크립터를 리턴한다. 만일 0보다 작으면 에러 출력이다.
 * @retval DEV_ERR_UNREGISTERED_DEVICE		장치 오류 : 등록되지 않은 장치
 * @retval DEV_ERR_ALREADY_OPEN			 	장치오류 : 이미 열려 있음
 * @retval DEV_ERR_NOT_INIT	  				장치 오류 : 초기화되지 않음
 */
int32_t dev_GpioOpen(const int8_t *devname, int32_t flags)
{
	int32_t devNum;
	int32_t readWrite = flags & DEV_RDWR;
	GPIO_InitTypeDef  GPIO_InitStructure;

	if(strcmp((const char*)devname, (const char*)DEV_GPIOA_DEVICE_NAME) == 0) {
		devNum = GPA;
	} else if(strcmp((const char*)devname, (const char*)DEV_GPIOB_DEVICE_NAME) == 0) {
		devNum = GPB;
	} else if(strcmp((const char*)devname, (const char*)DEV_GPIOC_DEVICE_NAME) == 0) {
		devNum = GPC;
	} else if(strcmp((const char*)devname, (const char*)DEV_GPIOD_DEVICE_NAME) == 0) {
		devNum = GPD;
	} else if(strcmp((const char*)devname, (const char*)DEV_GPIOE_DEVICE_NAME) == 0) {
		devNum = GPE;
	} else if(strcmp((const char*)devname, (const char*)DEV_GPIOF_DEVICE_NAME) == 0) {
		devNum = GPF;
	}

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA << devNum, ENABLE);
	/** Flag에 open 시 설정할 핀들을 설정한다 */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All & flags;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	/** 읽기전용 모드일 때 -> GPIO를 출력 모드로 설정 */

	if(readWrite == DEV_RDONLY)  {
		/**
		 * GPIO 모드 설정 : 여기서는 입력을 설정한다.
		 * GPIO_Mode_IN : GPIO를 입력으로 설정
		 * GPIO_Mode_OUT : GPIO를 출력으로 설정
		 * GPIO_Mode_AF : GPIO를 별도 기능을 하는 입출력 핀으로 설정
		 * GPIO_Mode_AN : GPIO를 아날로그 모드로 설정
		 */
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
		GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
		devGpioFlag[devNum].readInOut = READ_INPUT;
		/**쓰기전용 또는 읽기쓰기 모드링 때 -> GPIO를 출력 모드로 설정 */
	} else if((readWrite == DEV_RDWR) || (readWrite == DEV_WRONLY)) {
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
		/** GPIO 출력 타입 설정.
		 *
		 */
		GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
		/** 풀업/풀다운 모드 설정 -> 기본적으로 Pullup 설정 */
		GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
		devGpioFlag[devNum].readInOut = READ_OUTPUT;
	}

	GPIO_Init(gpio_Type[devNum], &GPIO_InitStructure);

	devGpioFlag[devNum].stat |= DEV_STAT_OPEN;

	return Dev_GPIOA + devNum;								/**< Device Descriptor를 리턴 */
}

/**
 * @brief GPIO 장치에 값을 쓴다.
 * GPIO 장치에 값을 쓴다는 것은 장치로 값을 출력한다는 의미이다.
 * @param dd 디바이스 디스크립터
 * @param buf 데이터 쓰기를 할 데이터 포인트
 * @param n 데이터의 길이
 * @return 쓰기를 수행한 데이터의 실제 사이즈
 */
ssize_t dev_GpioWrite(int32_t dd, const void *buf, size_t n)
{
	int32_t devNum = dd - Dev_GPIOA;
	if((devGpioFlag[devNum].stat & DEV_STAT_OPEN ) == 0)
		return DEV_ERR_NOT_OPEN;

	GPIO_Write(gpio_Type[devNum], (*(uint16_t*)buf));

	return 1;
}

/**
 * @brief GPIO 장치 값을 읽어들인다.
 * GPIO 장치에 값을 읽는 것은 장치로 값을 입력받는다는 의미이다.
 * @param dd 디바이스 디스크립터
 * @param buf 데이터 읽기를 할 데이터 포인트
 * @param nbytes 읽어들일 데이터의 최대 길이
 * @return 읽기를 수행한 데이터의 실제 사이즈
 */
ssize_t	dev_GpioRead(int32_t dd, void *buf, size_t nbytes)
{
	int32_t devNum = dd - Dev_GPIOA;
	if((devGpioFlag[devNum].stat & DEV_STAT_OPEN ) == 0)
		return DEV_ERR_NOT_OPEN;
	if(devGpioFlag[devNum].readInOut == READ_INPUT)				/**< readInOut이 READ_INPUT으로 설정된 경우 입력되는 값을 읽어들인다. */
		*((int16_t*)buf) = GPIO_ReadInputData(gpio_Type[devNum]);
	else														/**< readInOut이 READ_OUTPUT으로 설정된 경우 입력되는 값을 읽어들인다. */
		*((int16_t*)buf) = GPIO_ReadOutputData(gpio_Type[devNum]);
	return 1;
}

/**
 * @brief GPIO 장치를 설정한다.
 * GPIO 장치에 대해 읽기, 쓰기 이외의 동작을 수행할 경우 사용한다.
 * 만일 핀별로 다른 설정을 하고 싶을 경우 devIoctl을 이용하여 재설정하면 된다.
 * 핀별로 제어를 하고 싶은 경우에도 devIoctl로 할 수 있다.
 *
 * @param dd 디바이스 디스크립터
 * @param request 설정 명령어
 * @param data 설정값
 * @return 설정의 실제 결과
 */
ssize_t dev_GpioIoctl(int32_t dd, int32_t request, void* data)
{
	int32_t devNum = dd - Dev_GPIOA;

	if((devGpioFlag[devNum].stat & DEV_STAT_OPEN ) == 0)
		return DEV_ERR_NOT_OPEN;
	switch( request ){
	case DEV_GPIO_SET_BIT:
		GPIO_SetBits(gpio_Type[devNum], *((int16_t *)data));
		break;
	case DEV_GPIO_CLEAR_BIT:
		GPIO_ResetBits(gpio_Type[devNum], *((int16_t *)data));
		break;
	case DEV_GPIO_TOGGLE_BIT:
		GPIO_ToggleBits(gpio_Type[devNum], *((int16_t *)data));
		break;
	case DEV_GPIO_GET_INPUT_BIT:
		GPIO_ReadInputDataBit(gpio_Type[devNum], *((int16_t *)data));
		break;
	case DEV_GPIO_GET_OUTPUT_BIT:
		GPIO_ReadOutputDataBit(gpio_Type[devNum], *((int16_t *)data));
		break;
	case DEV_GPIO_CONFIG_BIT:
		GPIO_Init(gpio_Type[devNum], (GPIO_InitTypeDef*)data);
		break;
	case DEV_GPIO_CONFIG_INTERRUPT:
		dev_GpioConfigEXTI((uint8_t)devNum,(EXTI_Config *)data);
		break;
	default:
		return DEV_ERR_INVALID_ARG;
	}
	return 0;
}

/**
 * @brief GPIO 장치를 닫는다.
 * GPIO 장치를 더이상 사용하지 않는 경우 실행한다.
 * @param dd 디바이스 디스크립터
 * @return 성공여부
 */
int32_t dev_GpioClose(int32_t dd)
{
	int32_t devNum = dd - Dev_GPIOA;
	if((devGpioFlag[devNum].stat & DEV_STAT_OPEN ) == 0)
		return DEV_ERR_NOT_OPEN;

	devGpioFlag[devNum].stat &= ~(DEV_STAT_OPEN);

	GPIO_DeInit(gpio_Type[devNum]);
	return 0;
}

void dev_GpioConfigEXTI(uint8_t portsource, EXTI_Config* config)
{
	 EXTI_InitTypeDef   EXTI_InitStructure;
	 NVIC_InitTypeDef   NVIC_InitStructure;
	/** Enable SYSCFG clock */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

	/** Connect EXTI Line to GPIO Pin */
	SYSCFG_EXTILineConfig(portsource, config->pinsource);

	extiIsrFunc[config->pinsource] = config->func;
	/** configure EXTI */
	EXTI_InitStructure.EXTI_Line = 0x01 << config->pinsource;
	EXTI_InitStructure.EXTI_Mode = config->mode;
	EXTI_InitStructure.EXTI_Trigger = config->trigger;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);

	switch(config->pinsource) {
	case EXTI_PinSource0:
		NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;

		break;
	case EXTI_PinSource1:
		NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
		break;
	case EXTI_PinSource2:
		NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;
		break;
	case EXTI_PinSource3:
		NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;
		break;
	case EXTI_PinSource4:
		NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;
		break;
	case EXTI_PinSource5:
	case EXTI_PinSource6:
	case EXTI_PinSource7:
	case EXTI_PinSource8:
	case EXTI_PinSource9:
		NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
		break;
	case EXTI_PinSource10:
	case EXTI_PinSource11:
	case EXTI_PinSource12:
	case EXTI_PinSource13:
	case EXTI_PinSource14:
	case EXTI_PinSource15:
		NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
		break;
	}
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = config->priority;;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = config->subPriority;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

	NVIC_Init(&NVIC_InitStructure);

}

#ifdef USE_CMDLINE


/**
  * @brief  GPIO 장치를 열기 위한 함수에 대한 명령줄 처리
  * @param  argc 인자의 개수
  * @param  argv 문자열 인자들의 배열
  * @retval 0 : 성공, 0 이외의 값 : error
  * @retval CMDLINE_BAD_CMD         등록하지 않거나 문법에 맞지 않는 명령어가 입력되었을 때 리턴
  * @retval CMDLINE_TOO_MANY_ARGS	 해당 명령어에서 너무 많은 인자가 입력되었을 때 리턴
  * @retval CMDLINE_TOO_FEW_ARGS	해당 명령어에서 너무 적은 인자가 입력되었을 때 리턴
  * @retval CMDLINE_INVALID_ARGS	인자가 적정하지 않을 때 리턴
  */
int32_t dev_GpioOpenCmd(int32_t argc, int8_t *argv[])
{
	int32_t flags = 0;
	int32_t k = 0;
	int32_t err = 0;
	if(argc < 3)
		return CMDLINE_TOO_FEW_ARGS;
	DeviceStructure* device = deviceTable;

	while(device->devname != 0) {
		if(strcmp((char*)device->devname, (char*)argv[1]) == 0) {

			for(k = 2 ; k < argc ; k++) {

				if(strcmp((char*)argv[k], "readonly")  == 0) {
					flags |= DEV_RDONLY;
				}
				if(strcmp((char*)argv[k], "writeonly") == 0) {
					flags |= DEV_WRONLY;
				}
				if(strcmp((char*)argv[k], "readwrite") == 0) {
					flags |= DEV_RDWR;
				}
				if(strcmp((char*)argv[k], GPIO_ARG_PIN0) == 0) {
					flags |= GPIO_Pin_0;
				}
				if(strcmp((char*)argv[k],GPIO_ARG_PIN1) == 0) {
					flags |= GPIO_Pin_1;
				}
				if(strcmp((char*)argv[k],GPIO_ARG_PIN2) == 0) {
					flags |= GPIO_Pin_2;
				}
				if(strcmp((char*)argv[k],GPIO_ARG_PIN3) == 0) {
					flags |= GPIO_Pin_3;
				}
				if(strcmp((char*)argv[k],GPIO_ARG_PIN4) == 0) {
					flags |= GPIO_Pin_4;
				}
				if(strcmp((char*)argv[k],GPIO_ARG_PIN5) == 0) {
					flags |= GPIO_Pin_5;
				}
				if(strcmp((char*)argv[k],GPIO_ARG_PIN6) == 0) {
					flags |= GPIO_Pin_6;
				}
				if(strcmp((char*)argv[k],GPIO_ARG_PIN7) == 0) {
					flags |= GPIO_Pin_7;
				}
				if(strcmp((char*)argv[k],GPIO_ARG_PIN8) == 0) {
					flags |= GPIO_Pin_8;
				}
				if(strcmp((char*)argv[k],GPIO_ARG_PIN9) == 0) {
					flags |= GPIO_Pin_9;
				}
				if(strcmp((char*)argv[k],GPIO_ARG_PIN10) == 0) {
					flags |= GPIO_Pin_10;
				}
				if(strcmp((char*)argv[k],GPIO_ARG_PIN11) == 0) {
					flags |= GPIO_Pin_11;
				}
				if(strcmp((char*)argv[k],GPIO_ARG_PIN12) == 0) {
					flags |= GPIO_Pin_12;
				}
				if(strcmp((char*)argv[k],GPIO_ARG_PIN13) == 0) {
					flags |= GPIO_Pin_13;
				}
				if(strcmp((char*)argv[k],GPIO_ARG_PIN14) == 0) {
					flags |= GPIO_Pin_14;
				}
				if(strcmp((char*)argv[k],GPIO_ARG_PIN15) == 0) {
					flags |= GPIO_Pin_15;
				}
			}
			err = dev_GpioOpen(device->devname, flags);
			if(err != 0) {
				usbPrintf((int8_t*)"error occurred.\n");
				return CMDLINE_INVALID_ARGS;
			} else {
				usbPrintf((int8_t*)"Device %s is initialized.\n ", device->devname);
				return 0;
			}
		}
		device++;
	}
	return CMDLINE_INVALID_ARGS;
}


/**
  * @brief  GPIO 값을 읽기 위한 함수에 대한 명령줄 처리
  * @param  argc 인자의 개수
  * @param  argv 문자열 인자들의 배열
  * @retval 0 : 성공, 0 이외의 값 : error
  *     CMDLINE_BAD_CMD         등록하지 않거나 문법에 맞지 않는 명령어가 입력되었을 때 리턴
  *     CMDLINE_TOO_MANY_ARGS	 해당 명령어에서 너무 많은 인자가 입력되었을 때 리턴
  *     CMDLINE_TOO_FEW_ARGS	해당 명령어에서 너무 적은 인자가 입력되었을 때 리턴
  *     CMDLINE_INVALID_ARGS	인자가 적정하지 않을 때 리턴
  */
int32_t dev_GpioReadCmd(int32_t argc, int8_t *argv[])
{
	if(argc < 2)
		return CMDLINE_TOO_FEW_ARGS;
	DeviceStructure* device = deviceTable;
	uint16_t readData;
	while(device->devname != 0) {
		if(strcmp((char*)device->devname, (char*)argv[1]) == 0) {
			dev_GpioRead(device->dd, &readData, 1);
			usbPrintf((int8_t*)"read %s : %4x", argv[1], readData);
			return 0;
		}
		device++;
	}
	return CMDLINE_INVALID_ARGS;
}
/**
  * @brief  GPIO 출력을 위한 함수에 대한 명령줄 처리
  * @param  argc 인자의 개수
  * @param  argv 문자열 인자들의 배열
  * @retval 0 : 성공, 0 이외의 값 : error
  *     CMDLINE_BAD_CMD         등록하지 않거나 문법에 맞지 않는 명령어가 입력되었을 때 리턴
  *     CMDLINE_TOO_MANY_ARGS	 해당 명령어에서 너무 많은 인자가 입력되었을 때 리턴
  *     CMDLINE_TOO_FEW_ARGS	해당 명령어에서 너무 적은 인자가 입력되었을 때 리턴
  *     CMDLINE_INVALID_ARGS	인자가 적정하지 않을 때 리턴
  */
int32_t dev_GpioWriteCmd(int32_t argc, int8_t *argv[])
{
	if(argc < 3)
		return CMDLINE_TOO_FEW_ARGS;
	DeviceStructure* device = deviceTable;
	uint16_t writeData = (uint16_t)atoi((const char *)argv[2]);
	while(device->devname != 0) {
		if(strcmp((char*)device->devname, (char*)argv[1]) == 0) {
			dev_GpioWrite(device->dd, &writeData, 1);
			usbPrintf((int8_t*)"write %s : %4x", argv[1], writeData);
			return 0;
		}
		device++;
	}
	return CMDLINE_INVALID_ARGS;
}
/**
  * @brief  GPIO 설정을 위한 함수에 대한 명령줄 처리
  * @param  argc 인자의 개수
  * @param  argv 문자열 인자들의 배열
  * @retval 0 : 성공, 0 이외의 값 : error
  *     CMDLINE_BAD_CMD         등록하지 않거나 문법에 맞지 않는 명령어가 입력되었을 때 리턴
  *     CMDLINE_TOO_MANY_ARGS	 해당 명령어에서 너무 많은 인자가 입력되었을 때 리턴
  *     CMDLINE_TOO_FEW_ARGS	해당 명령어에서 너무 적은 인자가 입력되었을 때 리턴
  *     CMDLINE_INVALID_ARGS	인자가 적정하지 않을 때 리턴
  */
int32_t dev_GpioIoctlCmd(int32_t argc, int8_t *argv[])
{

	return 0;
}
/**
  * @brief  GPIO 종료를 위한 함수에 대한 명령줄 처리
  * @param  argc 인자의 개수
  * @param  argv 문자열 인자들의 배열
  * @retval 0 : 성공, 0 이외의 값 : error
  *     CMDLINE_BAD_CMD         등록하지 않거나 문법에 맞지 않는 명령어가 입력되었을 때 리턴
  *     CMDLINE_TOO_MANY_ARGS	 해당 명령어에서 너무 많은 인자가 입력되었을 때 리턴
  *     CMDLINE_TOO_FEW_ARGS	해당 명령어에서 너무 적은 인자가 입력되었을 때 리턴
  *     CMDLINE_INVALID_ARGS	인자가 적정하지 않을 때 리턴
  */
int32_t dev_GpioCloseCmd(int32_t argc, int8_t *argv[])
{
	if(argc < 2)
		return CMDLINE_TOO_FEW_ARGS;
	DeviceStructure* device = deviceTable;

	while(device->devname != 0) {
		if(strcmp((char*)device->devname, (char*)argv[1]) == 0) {
			dev_GpioClose(device->dd);
			usbPrintf((int8_t*)"Close %s ", argv[1]);
			return 0;
		}
	}
	return CMDLINE_INVALID_ARGS;
}
#endif /* USE_CMDLINE */
